package com.itheima.proxy;

import com.itheima.aop.Advice;
import com.itheima.service.StudentService;
import com.itheima.service.impl.StudentServiceImpl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class BeanProxyFactory {

    /*
        提供一个方法，返回StudentServiceImpl对象的代理对象
     */
    public static StudentService createBeanProxy(){
        //1 创建原始对象，也叫目标对象
        StudentService studentService=new StudentServiceImpl();

        //2 创建代理对象，难点
        /**
         * ClassLoader loader,类加载器，用于在内存中生成代理对象的class对象，有了class对象就可以反射创建代理对象。一般通过目标对象获取
         * Class<?>[] interfaces,告诉jvm代理对象要和目标对象实现相同的接口，传递目标对象一样的接口的class对象们
         * InvocationHandler h，用来处理代理对象要做的事，只要代理对象的任何方法被调用了，InvocationHandler内部的invoke方法就会执行
         *                      在invoke方法中就可以处理代理对象的增强逻辑。
         */
        ClassLoader loader=studentService.getClass().getClassLoader();
        Class<?>[] interfaces=studentService.getClass().getInterfaces();
        StudentService proxyObj = (StudentService) Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {
            /**
             * 处理代理对象增强的逻辑
             * @param proxy 表示代理对象
             * @param method 表示被调用的目标对象的方法对象
             * @param args 表示调用方法传递的参数
             * @return 哪里调用代理对象的方法，返回值就返回到哪里
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //怎么增强，在这个方法中写
                //System.out.println(method);
                //System.out.println(Arrays.toString(args));
                if (method.getName().equals("delete") || method.getName().equals("transfer")) {
                    Advice advice = new Advice();
                    //调用目标对象对应的方法执行具体的业务操作(CRUD),反射执行
                    Object value = null;
                    try {
                        //前置增强,开启事务
                        //advice.before();
                        //执行业务操作
                        value = method.invoke(studentService, args);
                        //后置增强，提交事务
                        //advice.afterReturn();
                    } catch (Exception e) {
                        e.printStackTrace();
                        //异常增强,回滚事务
                        //advice.afterThrowable();
                    } finally {
                        //最终增强,释放资源
                        advice.after();
                    }
                    return value;
                }else{
                    return method.invoke(studentService, args);
                }
            }
        });
        //3 返回代理对象
        return proxyObj;
    }
}
